﻿// -----------------------------------------------------------------------
// <copyright file="Role.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

using System.Data.Odbc;
using System.Linq;

namespace Centido.Core
{
    using System;
    using System.Collections.Generic;


    /// <summary>
    ///   A security role.
    /// </summary>
    public sealed class Role : IRemovable, IPrincipal, IRefreshable
    {
        /// <summary>
        ///   The current domain.
        /// </summary>
        private readonly Domain _domain;

        /// <summary>
        ///   The role name.
        /// </summary>
        private readonly string _roleName;

        /// <summary>
        ///   The display name of the role.
        /// </summary>
        private string _displayname;

        /// <summary>
        ///   Initializes a new instance of the <see cref="Centido.Core.Role"/> class
        /// for the specified role name and the specified domain.
        /// </summary>
        /// <param name = "roleName">The role name.</param>
        /// <param name = "domain">The current domain.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="roleName"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="domain"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="roleName"/> is an empty string.</exception>
        internal Role(string roleName, Domain domain)
        {
            if (roleName == null)
                throw new ArgumentNullException("roleName");
            if (roleName.Trim().Length == 0)
                throw new ArgumentException("Role name cannot be empty.");
            if (domain == null)
                throw new ArgumentNullException("domain");

            _roleName = roleName.Trim().ToLower();
            _domain = domain;
        }

        /// <summary>
        ///   Gets the current domain.
        /// </summary>
        public Domain Domain
        {
            get { return _domain; }
        }

        /// <summary>
        ///   Gets or sets the role display name.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in
        /// order to set this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to set this property.</exception>
        /// <example>
        ///   The following example shows how to set the display name of a security role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating two roles
        ///             domain.AddRole("first_role").DisplayName = "The first role";
        ///             domain.AddRole("second_role").DisplayName = "The second role";
        /// 
        ///             foreach(var role in domain.Roles)
        ///             {
        ///                 Console.WriteLine("Role: name = {0}, display name = {1}", role.Name, role.DisplayName);
        ///             }
        ///         }
        ///     }
        /// </code>
        /// </example>
        public string DisplayName
        {
            get { return _displayname ?? (_displayname = DbValue.GetString(
                ReadProperty(Db.Tables.RoleList.Col.DisplayName))); }
            set
            {
                if (value != null)
                    value = value.Trim();

                if (!string.IsNullOrEmpty(_displayname) && _displayname == value) return;

                WriteProperty(Db.Tables.RoleList.Col.DisplayName, value, OdbcType.NVarChar);

                _displayname = value;
            }
        }

        /// <summary>
        ///   Gets the users that were added to the security role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in
        /// order to read this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no
        /// permission to read this property.</exception>
        /// <example>
        ///   The following example shows how to get the users that were added to a security role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating the role
        ///             var role = domain.AddRole("my_role");
        /// 
        ///             //Creating a user
        ///             var user = domain.AddUser("my_user", "P@ssw0rd");
        /// 
        ///             //Adding the new user and the current user the role
        ///             role.AddUser(user);
        ///             role.AddUser(domain.CurrentUser);
        /// 
        ///             foreach(var u in role.Users)
        ///                 Console.WriteLine("User in the role: name = {0}", u.Name);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public ICollection<User> Users
        {
            get
            {
                var resultList = new List<User>();

                Domain.DbAccess.ExecuteReader(
                    cmd =>
                    {
                        cmd.CommandText = string.Format(
                            "select {0} from {1} where {2}=?",
                            Db.Tables.UserRolesList.Col.UserName,
                            Domain.GetObjectFullName(Db.Tables.UserRolesList.Name),
                            Db.Tables.UserRolesList.Col.ContainerRoleName);

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("role_name", OdbcType.NVarChar, Name));
                    },
                    reader => resultList.Add(new User(reader.GetString(Db.Tables.UserRolesList.Col.UserName), Domain)));

                return resultList;
            }
        }

        /// <summary>
        ///   Gets the roles that were added in the current role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order to read this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to read this property.</exception>
        /// <example>
        ///   The following example shows how to read the roles that were added in another role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating the role
        ///             var role = domain.AddRole("my_role");
        /// 
        ///             //Creating the child roles
        ///             var firstChildRole = domain.AddRole("first_child_role");
        ///             var secondChildRole = domain.AddRole("second_child_role");
        /// 
        ///             role.AddRole(firstChildRole);
        ///             role.AddRole(secondChildRole);
        /// 
        ///             foreach(var childRole in role.ChildRoles)
        ///                 Console.WriteLine("Child role: name = {0}", childRole.Name);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public ICollection<Role> ChildRoles
        {
            get
            {
                var resultList = new List<Role>();

                Domain.DbAccess.ExecuteReader(
                    cmd =>
                    {
                        cmd.CommandText = string.Format(
                            "select {0} from {1} where {2}=?",
                            Db.Tables.RoleRolesList.Col.RoleName,
                            Domain.GetObjectFullName(Db.Tables.RoleRolesList.Name),
                            Db.Tables.RoleRolesList.Col.ContainerRoleName);

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("container_role_name", OdbcType.NVarChar, Name));
                    },
                    reader => resultList.Add(new Role(reader.GetString(Db.Tables.RoleRolesList.Col.RoleName), Domain)));

                return resultList;
            }
        }

        /// <summary>
        ///   Gets the roles that contain the current role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order to read this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to read this property.</exception>
        /// <example>
        ///   The following example shows how to read the roles that contain the current role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating the role
        ///             var role = domain.AddRole("my_role");
        /// 
        ///             //Creating the parent roles
        ///             var firstParentRole = domain.AddRole("first_parent_role");
        ///             var secondParentRole = domain.AddRole("second_parent_role");
        /// 
        ///             firstParentRole.AddRole(role);
        ///             secondParentRole.AddRole(role);
        /// 
        ///             foreach(var parentRole in role.ParentRoles)
        ///                 Console.WriteLine("Parent role: name = {0}", parentRole.Name);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public ICollection<Role> ParentRoles
        {
            get
            {
                var resultList = new List<Role>();

                Domain.DbAccess.ExecuteReader(
                    cmd =>
                    {
                        cmd.CommandText = string.Format(
                            "select {0} from {1} where {2}=?",
                            Db.Tables.RoleRolesList.Col.ContainerRoleName,
                            Domain.GetObjectFullName(Db.Tables.RoleRolesList.Name),
                            Db.Tables.RoleRolesList.Col.RoleName);

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("role_name", OdbcType.NVarChar, Name));
                    },
                    reader => resultList.Add(new Role(reader.GetString(Db.Tables.RoleRolesList.Col.ContainerRoleName), Domain)));

                return resultList;
            }
        }

        /// <summary>
        ///   Gets the security principals that were added in the current role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order to read this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to read this property.</exception>
        /// <example>
        ///   The following example shows how to get the security principals that were added in the current role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating the role
        ///             var role = domain.AddRole("my_role");
        /// 
        ///             //Adding some some child roles
        ///             var firstChildRole = domain.AddRole("first_child_role");
        ///             var secondChildRole = domain.AddRole("second_child_role");
        /// 
        ///             role.AddRole(firstChildRole);
        ///             role.AddRole(secondChildRole);
        /// 
        ///             //Adding some users
        ///             var user = domain.AddUser("first_user", "P@ssw0rd");
        /// 
        ///             role.AddUser(user);
        ///             role.AddUser(domain.CurrentUser);
        /// 
        ///             foreach(var principal in role.Principals)
        ///                 Console.WriteLine("Principal: name = {0}", principal.Name);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public ICollection<IPrincipal> Principals
        {
            get
            {
                var resultList = ChildRoles.Cast<IPrincipal>().ToList();
                
                resultList.AddRange(Users.Cast<IPrincipal>());

                return resultList;
            }
        }

        /// <summary>
        ///   Gets the table permissions granted to the current role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order to read this property.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to read this property.</exception>
        /// <example>
        ///   The following example shows how to get the table permissions granted to a security role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///             
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting all permission on the table to the role
        ///             table.GrantAll(role);
        /// 
        ///             foreach(var perm in role.TablePermissions)
        ///                 Console.WriteLine("Role: table permission = {0}", perm.DataAction);
        ///         }
        ///     }
        /// </code>
        /// </example>
        public ICollection<TablePermission> TablePermissions
        {
            get
            {
                var resultList = new List<TablePermission>();

                Domain.DbAccess.ExecuteReader(
                    cmd =>
                    {
                        cmd.CommandText = string.Format(
                            "select {0}, {1} from {2} where {3}=?",
                            Db.Tables.TableAcl.Col.TableId,
                            Db.Tables.TableAcl.Col.DataAction,
                            Domain.GetObjectFullName(Db.Tables.TableAcl.Name),
                            Db.Tables.TableAcl.Col.PrincipalName);

                        cmd.Parameters.Add(Domain.DbAccess.CreateParameter("principal_name", OdbcType.NVarChar, Name));
                    },
                    reader =>
                    {
                        var tableId = reader.GetGuid(Db.Tables.TableAcl.Col.TableId)
                            .GetValueOrDefault();
                        var dataActionValue = reader.GetInteger(Db.Tables.TableAcl.Col.DataAction)
                            .GetValueOrDefault();

                        var dataAction = (DataAction)dataActionValue;

                        resultList.Add(new TablePermission(new Table(tableId, Domain), Name, dataAction));
                    });

                return resultList;
            }
        }

        /// <summary>
        ///   Gets the role name.
        /// </summary>
        public string Name
        {
            get { return _roleName; }
        }

        /// <summary>
        ///   Deletes the current role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order to execute this function.</remarks>
        /// <example>
        ///   The following example shows how a security role is deleted.
        /// <code>
        ///         using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///             
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting all permission on the table to the role
        ///             table.GrantAll(role);
        /// 
        ///             //Adding a user to the role
        ///             role.AddUser(domain.CurrentUser);
        /// 
        ///             //Adding another role to the role
        ///             var childRole = domain.AddRole("child_role");
        ///             role.AddRole(childRole);
        /// 
        ///             //Adding the role to another role
        ///             var parentRole = domain.AddRole("parent_role");
        ///             parentRole.AddRole(role);
        /// 
        ///             Console.WriteLine("Table: permission count = {0}", table.Permissions.Count());
        ///             Console.WriteLine("Current user: role count = {0}", domain.CurrentUser.Roles.Count());
        ///             Console.WriteLine("Child role: parent role count = {0}", childRole.ParentRoles.Count());
        ///             Console.WriteLine("Parent role: child role count = {0}", parentRole.ChildRoles.Count());
        /// 
        ///             Console.WriteLine("Deleting the role");
        /// 
        ///             role.Delete();
        /// 
        ///             Console.WriteLine("Table: permission count = {0}", table.Permissions.Count());
        ///             Console.WriteLine("Current user: role count = {0}", domain.CurrentUser.Roles.Count());
        ///             Console.WriteLine("Child role: parent role count = {0}", childRole.ParentRoles.Count());
        ///             Console.WriteLine("Parent role: child role count = {0}", parentRole.ChildRoles.Count());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void Delete()
        {
            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?)}}",
                        Domain.GetObjectFullName(Db.Procedures.DeleteRole));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_role_name", OdbcType.NVarChar, Name));
                });

            // Deleting the role from the cache
            Domain.DeleteRoleFromCache(this);
        }

        /// <summary>
        ///   Checks the existence of the role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change the security settings in order
        /// to execute this function.</remarks>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user
        /// has no permission to execute this function.</exception>
        /// <returns>Returns true if the role still exists; otherwise, returns false.</returns>
        /// <example>
        ///   The following example shows how to cheack the existence of a role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             Console.WriteLine("Role exists = {0}", role.Exists());
        /// 
        ///             Console.WriteLine("Deleting the role");
        /// 
        ///             role.Delete();
        /// 
        ///             Console.WriteLine("Role exists = {0}", role.Exists());
        ///         }
        ///     }
        /// </code>
        /// </example>
        public bool Exists()
        {
            var wasFound = false;

            Domain.DbAccess.ExecuteScalar(
                cmd =>
                {
                    cmd.CommandText = string.Format("select count(*) from {0} where {1}=?",
                        Domain.GetObjectFullName(Db.Tables.RoleList.Name),
                        Db.Tables.RoleList.Col.RoleName);

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("name", OdbcType.NVarChar, Name));
                },
                result => wasFound = DbValue.GetInteger(result) != 0);

            return wasFound;
        }

        /// <summary>
        ///   Adds the specified user to the current security role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order to execute this function.</remarks>
        /// <param name = "user">The user to be added to the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="user"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the specified user was already added to the current security role.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <example>
        ///   The following example shows how to add a user to a security role.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting permissions on the table to the role
        ///             table.GrantAll(role);
        /// 
        ///             //Trying to insert into the table without permissions
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("Cannot insert into the table without permissions");
        ///             }
        /// 
        ///             //Adding the current user to the role
        ///             role.AddUser(domain.CurrentUser);
        /// 
        ///             //Inserting into the table
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void AddUser(IUser user)
        {
            if (user == null)
                throw new ArgumentNullException("user");

            AddUser(user.Name);
        }

        /// <summary>
        ///   Adds a user with the specified name to the current security role.
        /// </summary>
        /// <remarks>
        /// <para>The name of the user to be added to the current security role is lowered and trimmed.</para>
        /// <para>The current user has to have the permission to change security settings in order to execute this function.</para>
        /// </remarks>
        /// <param name="userName">The name of the user to be added to the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="userName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="userName"/> is an empty string.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when a user with the same name was already added to the current security role.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <example>
        ///   The following example shows how to add a user with the specified name to a security role.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting permissions on the table to the role
        ///             table.GrantAll(role);
        /// 
        ///             //Trying to insert into the table without permissions
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("Cannot insert into the table without permissions");
        ///             }
        /// 
        ///             //Adding the current user to the role
        ///             role.AddUser(domain.CurrentUser.Name);
        /// 
        ///             //Inserting into the table
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void AddUser(string userName)
        {
            if (userName == null)
                throw new ArgumentNullException("userName");
            if (userName.Trim().Length == 0)
                throw new ArgumentException("User name cannot be empty.");

            userName = userName.Trim().ToLower();

            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?,?)}}", 
                        Domain.GetObjectFullName(Db.Procedures.AddUserInRole));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_user_name", OdbcType.NVarChar, userName));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_role_name", OdbcType.NVarChar, Name));
                });
        }

        /// <summary>
        ///   Checks that the current security role contains the specified user.
        /// </summary>
        /// <remarks>
        ///   The current user has to have the permission to change security settings in order
        /// to execute this function.
        /// </remarks>
        /// <param name = "user">The specified user.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="user"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <returns>Returns true if the current security role contains the specified user;
        /// otherwise, false.</returns>
        /// <example>
        ///    The following example shows how to check that a security role contains the specified user.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             //Creating a user
        ///             var user = domain.AddUser("my_user", "P@ssw0rd");
        /// 
        ///             //Adding the user to the role
        ///             role.AddUser(user);
        /// 
        ///             //Checking the role users
        ///             Console.WriteLine("The role contains 'my_user' = {0}", role.ContainsUser(user));
        ///             Console.WriteLine("The role contains the current user = {0}",
        ///                 role.ContainsUser(domain.CurrentUser));
        ///         }
        ///     }
        /// </code>
        /// </example>
        public bool ContainsUser(IUser user)
        {
            if (user == null)
                throw new ArgumentNullException("user");

            return ContainsUser(user.Name);
        }

        /// <summary>
        ///   Checks that the current security role contains a user with the specified name.
        /// </summary>
        /// <remarks>
        /// <para>The name of the user is lowered and trimmed.</para>
        /// <para>The current user has to have the permission to change security settings in order
        /// to execute this function.</para>
        /// </remarks>
        /// <param name = "userName">The name of the user.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="userName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="userName"/> is an empty string.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <returns>Returns true if the current security role contains a user with the specified name;
        /// otherwise, false.</returns>
        /// <example>
        ///    The following example shows how to check that a security role contains a user with the specified name.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             //Creating a user
        ///             var user = domain.AddUser("my_user", "P@ssw0rd");
        /// 
        ///             //Adding the user to the role
        ///             role.AddUser(user);
        /// 
        ///             //Checking the role users
        ///             Console.WriteLine("The role contains 'my_user' = {0}", role.ContainsUser(user.Name));
        ///             Console.WriteLine("The role contains the current user = {0}",
        ///                 role.ContainsUser(domain.CurrentUser.Name));
        ///         }
        ///     }
        /// </code>
        /// </example>
        public bool ContainsUser(string userName)
        {
            if (userName == null)
                throw new ArgumentNullException("userName");
            if (userName.Trim().Length == 0)
                throw new ArgumentException("User name cannot be empty.");

            userName = userName.Trim().ToLower();

            var userWasFound = false;

            Domain.DbAccess.ExecuteScalar(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "select 1 from {0} where {1}=? and {2}=?",
                        Domain.GetObjectFullName(Db.Tables.UserRolesList.Name),
                        Db.Tables.UserRolesList.Col.ContainerRoleName,
                        Db.Tables.UserRolesList.Col.UserName);

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("role_name", OdbcType.NVarChar, Name));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("user_name", OdbcType.NVarChar, userName));
                },
                result => { userWasFound = DbValue.GetInteger(result) == 1; });

 
            return userWasFound;
        }

        /// <summary>
        ///   Deletes the specified user from the current security role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order
        /// to execute this function.</remarks>
        /// <param name = "user">The user to be deleted from the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="user"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current security role doesn't contain
        /// the specified user.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission
        /// to execute this function.</exception>
        /// <example>
        ///   The following example shows how to delete the specified user from a security role.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting table permission to the role
        ///             table.GrantAll(role);
        /// 
        ///             //Adding the current user to the role
        ///             role.AddUser(domain.CurrentUser);
        /// 
        ///             //Inserting into the table
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        /// 
        ///             //Deleting the current user from the role
        ///             role.RemoveUser(domain.CurrentUser);
        /// 
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("The current user has no permission to insert into the table");
        ///             }
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void RemoveUser(IUser user)
        {
            if (user == null)
                throw new ArgumentNullException("user");

            RemoveUser(user.Name);
        }

        /// <summary>
        ///   Deletes a user with the specified name from the current security role.
        /// </summary>
        /// <remarks>
        /// <para>The name of the user to be deleted from the current security role is lowered and trimmed.</para>
        /// <para>The current user has to have the permission to change security settings in order
        /// to execute this function.</para>
        /// </remarks>
        /// <param name = "userName">The name of the user to be deleted from the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="userName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="userName"/> is an empty string.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current security role doesn't contain
        /// a user with the specified name.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission
        /// to execute this function.</exception>
        /// <example>
        ///   The following example shows how to delete a user with the specified name from a security role.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating a role
        ///             var role = domain.AddRole("my_role");
        ///          
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting table permission to the role
        ///             table.GrantAll(role);
        /// 
        ///             //Adding the current user to the role
        ///             role.AddUser(domain.CurrentUser);
        /// 
        ///             //Inserting into the table
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        /// 
        ///             //Deleting the current user from the role
        ///             role.RemoveUser(domain.CurrentUser.Name);
        /// 
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("The current user has no permission to insert into the table");
        ///             }
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void RemoveUser(string userName)
        {
            if (userName == null)
                throw new ArgumentNullException("userName");
            if (userName.Trim().Length == 0)
                throw new ArgumentException("User name cannot be empty.");

            userName = userName.Trim().ToLower();

            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?,?)}}", 
                        Domain.GetObjectFullName(Db.Procedures.DeleteUserFromRole));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_user_name", OdbcType.NVarChar, userName));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_role_name", OdbcType.NVarChar, Name));
                });
        }

        /// <summary>
        ///   Adds another security role to the current security role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings
        /// in order to execute this function.</remarks>
        /// <param name = "roleToAdd">The security role to be added to the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="roleToAdd"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the security role was already added to the current security role.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when a cycle of security roles is formed.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <example>
        ///   The following example shows how to add a security role to another security role.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating two roles
        ///             var parentRole = domain.AddRole("parent_role");
        ///             var childRole = domain.AddRole("child_role");
        ///          
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        ///             
        ///             //Granting table permissions to the parent role
        ///             table.GrantAll(parentRole);
        /// 
        ///             //Adding the current user to the child role
        ///             childRole.AddUser(domain.CurrentUser);
        /// 
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("The current user has no permission to insert into the table");
        ///             }
        /// 
        ///             //Adding the child role to the parent one
        ///             parentRole.AddRole(childRole);
        /// 
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void AddRole(Role roleToAdd)
        {
            if (roleToAdd == null)
                throw new ArgumentNullException("roleToAdd");

            AddRole(roleToAdd.Name);
        }

        /// <summary>
        ///   Adds a security role with the specified name to the current security role.
        /// </summary>
        /// <remarks>
        /// <para>The name of a security role to be added to the current security role is lowered
        /// and trimmed.</para>
        /// <para>The current user has to have the permission to change security settings
        /// in order to execute this function.</para></remarks>
        /// <param name = "roleToAddName">The name of the security role to be added to the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="roleToAddName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="roleToAddName"/> is an empty string.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when a security role with the same name was already added to the current security role.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when a cycle of security roles is formed.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission to execute this function.</exception>
        /// <example>
        ///   The following example shows how to add a security role with the specified name to another security role.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating two roles
        ///             var parentRole = domain.AddRole("parent_role");
        ///             var childRole = domain.AddRole("child_role");
        ///          
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        ///             
        ///             //Granting table permissions to the parent role
        ///             table.GrantAll(parentRole);
        /// 
        ///             //Adding the current user to the child role
        ///             childRole.AddUser(domain.CurrentUser);
        /// 
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException)
        ///             {
        ///                 Console.WriteLine("The current user has no permission to insert into the table");
        ///             }
        /// 
        ///             //Adding the child role to the parent one
        ///             parentRole.AddRole(childRole.Name);
        /// 
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void AddRole(string roleToAddName)
        {
            if (roleToAddName == null)
                throw new ArgumentNullException("roleToAddName");
            if (roleToAddName.Trim().Length == 0)
                throw new ArgumentException("Role name cannot be empty.");

            roleToAddName = roleToAddName.Trim().ToLower();

            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?,?)}}",
                        Domain.GetObjectFullName(Db.Procedures.AddRoleInRole));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_role_name", OdbcType.NVarChar, roleToAddName));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_container_role_name", OdbcType.NVarChar, Name));
                });
        }

        /// <summary>
        ///   Checks that the current security role contains the specified security role.
        /// </summary>
        /// <remarks>
        /// The current user has to have the permission to change security settings in order
        /// to execute this function.
        /// </remarks>
        /// <param name = "role">The specified security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="role"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission
        /// to execute this function.</exception>
        /// <returns>Returns true if the current security role contains
        /// the specified security role; otherwise, false.</returns>
        /// <example>
        ///   The following example shows how to check that a security role contains another security role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating three roles
        ///             var parentRole = domain.AddRole("parent_role");
        ///             var childRole_1 = domain.AddRole("child_role_1");
        ///             var childRole_2 = domain.AddRole("child_role_2");
        /// 
        ///             //Adding the first child role to the parent role
        ///             parentRole.AddRole(childRole_1);
        ///             
        ///             Console.WriteLine("Parent role contains the first child role = {0}",
        ///                 parentRole.ContainsRole(childRole_1));
        ///             Console.WriteLine("Parent role contains the second child role = {0}",
        ///                 parentRole.ContainsRole(childRole_2));
        ///         }
        ///     }
        /// </code>
        /// </example>
        public bool ContainsRole(Role role)
        {
            if (role == null)
                throw new ArgumentNullException("role");
            
            return ContainsRole(role.Name);
        }

        /// <summary>
        ///   Checks that the current security role contains a security role with the specified name.
        /// </summary>
        /// <remarks>
        /// <para>The name of the security role is lowered and trimmed.</para>
        /// <para>The current user has to have the permission to change security settings in order
        /// to execute this function.</para>
        /// </remarks>
        /// <param name = "roleName">The specified security role name.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="roleName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="roleName"/> is an empty string.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission
        /// to execute this function/</exception>
        /// <returns>Returns true if the current security role contains
        /// a security role with the specified name; otherwise, false.</returns>
        /// <example>
        ///   The following example shows how to check that a security role contains another security role.
        /// <code>
        ///     using System;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating three roles
        ///             var parentRole = domain.AddRole("parent_role");
        ///             var childRole_1 = domain.AddRole("child_role_1");
        ///             var childRole_2 = domain.AddRole("child_role_2");
        /// 
        ///             //Adding the first child role to the parent role
        ///             parentRole.AddRole(childRole_1);
        ///             
        ///             Console.WriteLine("Parent role contains the first child role = {0}",
        ///                 parentRole.ContainsRole(childRole_1.Name));
        ///             Console.WriteLine("Parent role contains the second child role = {0}",
        ///                 parentRole.ContainsRole(childRole_2.Name));
        ///         }
        ///     }
        /// </code>
        /// </example>
        public bool ContainsRole(string roleName)
        {
            if (roleName == null)
                throw new ArgumentNullException("roleName");
            if (roleName.Trim().Length == 0)
                throw new ArgumentException("Role name cannot be empty.");

            roleName = roleName.Trim().ToLower();

            var roleWasFound = false;

            Domain.DbAccess.ExecuteScalar(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "select 1 from {0} where {1}=? and {2}=?",
                        Domain.GetObjectFullName(Db.Tables.RoleRolesList.Name),
                        Db.Tables.RoleRolesList.Col.ContainerRoleName,
                        Db.Tables.RoleRolesList.Col.RoleName);

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("container_role_name", OdbcType.NVarChar, Name));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("role_name", OdbcType.NVarChar, roleName));
                },
                result => roleWasFound = DbValue.GetInteger(result) == 1);

            return roleWasFound;
        }

        /// <summary>
        ///   Removes the specified security role from the current security role.
        /// </summary>
        /// <remarks>The current user has to have the permission to change security settings in order
        /// to execute this function.</remarks>
        /// <param name = "roleToDelete">The security role to be deleted from the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="roleToDelete"/> is null.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current security role
        /// doesn't have the specified security role.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission
        /// to execute this function.</exception>
        /// <example>
        ///   The following example shows how to delete a security role from another one.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating two roles
        ///             var parentRole = domain.AddRole("parent_role");
        ///             var childRole = domain.AddRole("child_role");
        /// 
        ///             //Adding the child role to the parent one
        ///             parentRole.AddRole(childRole);
        /// 
        ///             //Adding the current user to the child role
        ///             childRole.AddUser(domain.CurrentUser);
        /// 
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting table permission to the parent role
        ///             table.GrantAll(parentRole);
        /// 
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        /// 
        ///             //Deleting the child role from the parent one
        ///             parentRole.RemoveRole(childRole);
        /// 
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException) 
        ///             {
        ///                 Console.WriteLine("The current user has no insert permission on the table");
        ///             }
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void RemoveRole(Role roleToDelete)
        {
            if (roleToDelete == null)
                throw new ArgumentNullException("roleToDelete");

            RemoveRole(roleToDelete.Name);
        }

        /// <summary>
        ///   Removes a security role with the specified name from the current security role.
        /// </summary>
        /// <remarks>
        /// <para>The name of the security role to be deleted from the current security role
        /// is lowered and trimmed.</para>
        /// <para>The current user has to have the permission to change security settings in order
        /// to execute this function.</para></remarks>
        /// <param name = "roleToDeleteName">The name of the security role to be deleted from the current security role.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="roleToDeleteName"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown when the value of <paramref name="roleToDeleteName"/> is an empty string.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current security role
        /// doesn't have a security role with the specified name.</exception>
        /// <exception cref="System.Data.Common.DbException">Thrown when the current user has no permission
        /// to execute this function.</exception>
        /// <example>
        ///   The following example shows how to delete a security role from another one.
        /// <code>
        ///     using System;
        ///     using System.Data.Common;
        ///     using Centido.Core;
        /// 
        ///     class Sample
        ///     {
        ///         static void Main()
        ///         {
        ///             var domainConfig = new DomainConfiguration()
        ///             {
        ///                 DbConnectionString = @"Driver={SQL Server};Server=.\SQLEXPRESS;Database=MyDb;Uid=admin;Pwd=P@ssw0rd;",
        ///                 DbProviderName = "MSSQLSERVER"
        ///             };
        ///         
        ///             var domain = Domain.Build(domainConfig);
        ///         
        ///             domain.DeleteAll();
        ///             
        ///             //Creating two roles
        ///             var parentRole = domain.AddRole("parent_role");
        ///             var childRole = domain.AddRole("child_role");
        /// 
        ///             //Adding the child role to the parent one
        ///             parentRole.AddRole(childRole);
        /// 
        ///             //Adding the current user to the child role
        ///             childRole.AddUser(domain.CurrentUser);
        /// 
        ///             //Creating a table
        ///             var table = domain.AddTable("my_table");
        /// 
        ///             //Granting table permission to the parent role
        ///             table.GrantAll(parentRole);
        /// 
        ///             table.InsertRow();
        /// 
        ///             Console.WriteLine("The insert operation was successful");
        /// 
        ///             //Deleting the child role from the parent one
        ///             parentRole.RemoveRole(childRole.Name);
        /// 
        ///             try
        ///             {
        ///                 table.InsertRow();
        ///             }
        ///             catch(DbException) 
        ///             {
        ///                 Console.WriteLine("The current user has no insert permission on the table");
        ///             }
        ///         }
        ///     }
        /// </code>
        /// </example>
        public void RemoveRole(string roleToDeleteName)
        {
            if (roleToDeleteName == null)
                throw new ArgumentNullException("roleToDeleteName");
            if (roleToDeleteName.Trim().Length == 0)
                throw new ArgumentException("Role name cannot be empty.");

            roleToDeleteName = roleToDeleteName.Trim().ToLower();

            Domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format("{{call {0}(?,?)}}",
                        Domain.GetObjectFullName(Db.Procedures.RemoveRoleFromRole));

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_role_name", OdbcType.NVarChar, roleToDeleteName));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("a_container_role_name", OdbcType.NVarChar, Name));
                });
        }

        /// <summary>
        ///   Reads the current security role property.
        /// </summary>
        /// <param name = "propertyName">The property name.</param>
        /// <returns>Returns the property value.</returns>
        private object ReadProperty(string propertyName)
        {
            object propertyValue = null;

            _domain.DbAccess.ExecuteScalar(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "select {0} from {1} where {2}=?",
                        propertyName,
                        Domain.GetObjectFullName(Db.Tables.RoleList.Name),
                        Db.Tables.RoleList.Col.RoleName);

                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("role_name", OdbcType.NVarChar, Name));
                },
                result => propertyValue = result);

            return propertyValue;
        }

        /// <summary>
        ///   Updates the current security role property.
        /// </summary>
        /// <param name = "propertyName">The property name.</param>
        /// <param name = "propertyValue">The property value.</param>
        /// <param name = "propertyType">The property database type.</param>
        private void WriteProperty(string propertyName, object propertyValue, OdbcType propertyType)
        {
            var rowCount = _domain.DbAccess.ExecuteNonQuery(
                cmd =>
                {
                    cmd.CommandText = string.Format(
                        "update {0} set {1}=? where {2}=?",
                        Domain.GetObjectFullName(Db.Tables.RoleList.Name),
                        propertyName,
                        Db.Tables.RoleList.Col.RoleName);

                    cmd.Parameters.Add(
                        Domain.DbAccess.CreateParameter("value", propertyType, DbValue.GetDbValue(propertyValue)));
                    cmd.Parameters.Add(Domain.DbAccess.CreateParameter("role_name", OdbcType.NVarChar, Name));
                });

            if (rowCount < 1)
                throw new DbOperationException();
        }

        /// <summary>
        ///   Refreshes the properties of the role.
        /// </summary>
        public void Refresh()
        {
            _displayname = null;
        }
    }
}